using System;
using System.Collections.Generic;
using CHEnhanceEfCore.Config.MQ.listen;
using CHEnhanceEfCore.System;
using Microsoft.Extensions.DependencyInjection;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace CHEnhanceEfCore.Config.MQ.factory
{
    public class RabbitMqFactory
    {
        private readonly AppSettings _appSettings;
        private ConnectionFactory _connectionFactory;
        private IConnection _connection;
        private readonly IServiceCollection _serviceCollection;

        public RabbitMqFactory(AppSettings appSettings, IServiceCollection serviceCollection)
        {
            _appSettings = appSettings;
            _serviceCollection = serviceCollection;
        }

        public void init()
        {
            Console.WriteLine("******init RabbitMq start******");
            configFactory();
            //队列声明
            queueDeclare();
            //交换机声明
            exchangeDeclare();
            //交换机和队列进行绑定
            queueBind();
            //注册监听器
            registerListen();
            Console.WriteLine("******init RabbitMq end******");
        }

        private void registerListen()
        {
            using var scope = _serviceCollection.BuildServiceProvider().CreateScope();
            Dictionary<string, IQueueListen> queueListenMap = new();
            IEnumerable<IQueueListen> queueListens = scope.ServiceProvider.GetServices<IQueueListen>();
            foreach (var queueListen in queueListens)
            {
                MqListenAttribute[] customAttributes = (MqListenAttribute[]) queueListen.GetType().GetCustomAttributes(typeof(MqListenAttribute), false);
                if (customAttributes.Length > 0)
                {
                    var mqListenAttribute = customAttributes[0];
                    var name = mqListenAttribute.name;
                    if (string.IsNullOrWhiteSpace(name))
                    {
                        Console.WriteLine(queueListen.GetType().FullName +
                                          "registerListen fail,reason is not like[MqListen(\"orderQueue\")]");
                        continue;
                    }

                    queueListenMap.Add(name, queueListen);
                }
            }

            var channel = _connection.CreateModel();
            foreach (var config in _appSettings.queueConfigs)
            {
                var queueListen = queueListenMap[config.queueName];
                var eventingBasicConsumer = new EventingBasicConsumer(channel);
                if (config.prefetchCount != 0)
                {
                    //0表示不限制未确认消息的总大小
                    //config.prefetchCount表示每个消费者在确认任何消息之前可以接收的最大未确认消息数 
                    //global设置为 true，则将此 QoS 设置应用于所有通道，否则将其应用于当前通道。通常将其设置为 false。
                    channel.BasicQos(0, config.prefetchCount, false);
                }

                Action<ulong, bool> action = null;
                if (!config.isAutoAck)
                {
                    action = (deliveryTag, multiple) => { channel.BasicAck(deliveryTag, multiple); };
                }

                queueListen.startHandleMessage(eventingBasicConsumer, action);
                channel.BasicConsume(config.queueName, config.isAutoAck, eventingBasicConsumer);
            }
        }

        private void queueBind()
        {
            int total = 0;
            var channel = _connection.CreateModel();
            foreach (var config in _appSettings.queueBindConfigs)
            {
                channel.QueueBind(config.queueName, config.exchangeName, config.routingKey);
                total++;
            }

            Console.WriteLine("queueBind total===>" + total);
        }

        private void queueDeclare()
        {
            int total = 0;
            var channel = _connection.CreateModel();
            foreach (var config in _appSettings.queueConfigs)
            {
                channel.QueueDeclare(config.queueName, config.durable, config.exclusive, config.autoDelete,
                    config.arguments);
                total++;
            }

            Console.WriteLine("queueDeclare total===>" + total);
        }

        private void exchangeDeclare()
        {
            int total = 0;
            var channel = _connection.CreateModel();
            foreach (var config in _appSettings.exchangeConfigs)
            {
                channel.ExchangeDeclare(config.exchangeName, config.type, config.durable, config.autoDelete,
                    config.arguments);
                total++;
            }

            Console.WriteLine("queueDeclare total===>" + total);
        }
        
        private void configFactory()
        {
            _connectionFactory = new ConnectionFactory();
            //可以通过配置进行更改
            // {
            // HostName = _appSettings.MqEndpoint,
            // UserName = _appSettings.MqUserName,
            // Password = _appSettings.MqPassword
            //};
            _connection = _connectionFactory.CreateConnection();
        }

        public IModel getChannel()
        {
            return _connection.CreateModel();
        }
    }
}